package model.ability;

import model.core.Logger;
import model.effects.Effect;
import model.entity.Entity;
import model.map.MapPoint;
import model.map.MapPointTreeNode;

/**
 * This class defines abilities that can be done anywhere on the map
 * by the caster, from a hotkey.
 * @author Zachary
 */
public class RangedMapAbility extends DurationAbility {
	private int MAXRANGE = 20;
	private int MINRANGE = 3;
	private PlacementAlgorithm placementAlgorithm;
	private int propogationDelay;
	
	/**
	 * Constructor for a RangedMapAbility.
	 */
	public RangedMapAbility(String name, PassiveSkill ps, int mana, int delay,
			Effect baseEffect, AbilityType at, String graphicID, PlacementAlgorithm pa, 
			int duration, int propogationDelay) {
		super(name, ps, mana, delay, baseEffect, at, graphicID, duration);
		this.placementAlgorithm = pa;
		this.propogationDelay = propogationDelay;
	}
	
	/**
	 * Constructor for a RangedMapAbility with added parameters for
	 * min and max range.
	 */
	public RangedMapAbility(String name, PassiveSkill ps, int mana, int delay,
			Effect baseEffect, AbilityType at, String graphicID, PlacementAlgorithm pa, 
			int duration, int minRange, int maxRange, int propogationDelay) {
		super(name, ps, mana, delay, baseEffect, at, graphicID, duration);
		this.placementAlgorithm = pa;
		this.MAXRANGE = maxRange;
		if(minRange > maxRange)
			this.MINRANGE = maxRange;
		else
			this.MINRANGE = minRange;
		this.propogationDelay = propogationDelay;
	}
	
	/**
	 * Call this method to use a RangedMapAbility.
	 * @param h
	 */
	public void useMapAbility(Entity caster){
		if(this.testProbability())
			this.doRangedAbility(caster);
		else
			Logger.getInstance().writeToLogger("Ability failed!");
		caster.diasbleAttack(this.getDelay());
	}
	
	/**
	 * Propogates ability when called.
	 */
	private void doRangedAbility(Entity caster){
		MapPoint originPoint = caster.getLocation();
		MapPointTreeNode head = createPlacementTree(caster.getDirection());
		RangedAbilityHandler h = HandlerFactory.createRangedAbilityHandler();
		Effect effect = this.getDerivedEffect(caster);
		h.run(this, head, propogationDelay, effect, caster, originPoint);
	}
	
	/**
	 * Creates the map point tree that will be used to generate
	 * the SkillObject tree by the RangedAbilityHandler.
	 * @param direction
	 * @return
	 */
	private MapPointTreeNode createPlacementTree(MapPoint direction){
		return this.placementAlgorithm.calculateDisplacementSet(direction, this.calculateRange());
	}
	
	/**
	 * Calculates the value of the ability's effect radius.
	 * @return
	 */
	private int calculateRange(){
		return Math.max(MINRANGE + this.getGoverningSkillLevel(), MAXRANGE);
	}

}
